/*Yipeng Huang and Scott Rogowski*/
/*yh2315 smr2167*/

//The MipsPipeline will facilitate the interactions between the five stages of the mips pipeline calling each of the five modules individually in their order
module mipspipe (
				clk, reset, 
				
				//From the given instruction module				
				inst_i_valid, inst_i, 
				inst_o_valid, inst_o_addr,

				//From the given data module
				data_i_valid, data_i,
				data_o_valid, data_o_rw,
				data_o_addr, data_o_value
				
/*				debug0,
				debug1,
				debug2,
				debug3
*/				);
	
	//Basic inputs
	input clk;
	input reset;
	
	//From the given instruction module				
	input inst_i_valid;
	input [31:0] inst_i; 
	output inst_o_valid;
	output [31:0] inst_o_addr;

	//From the given data module
	input data_i_valid;
	input [31:0] data_i;
	output data_o_valid;
	output data_o_rw;
	output [31:0] data_o_addr;
	output [31:0] data_o_value;

/*	//debug
	output [31:0] debug0,debug1,debug2,debug3;
*/
	//The pause.  We will turn this on when instruction memory or data memory do not respond on same clock cycle
	wire pause;
	wire inst_delay_exception;
	wire data_delay_exception;
	assign pause = inst_delay_exception | data_delay_exception;
	
	///////////////////////////////////////////////////////////
	///////////////////*HAZARD DETECTION*//////////////////////
	///////////////////////////////////////////////////////////
	
	wire bubble_hd;
	wire [31:0] instructions_dh;
	wire [31:0] waiting_on_writeback_dh;
	wire enable_wait_for_hd;
	wire [4:0] set_wait_for_hd;
	wire jump_ef; //If jump, change the source
	wire branch_em; // Control bit for branch commands
		
	HazardDetectionUnit myHazard (
									.clk(clk),
									.reset(reset),
									.bubble(bubble_hd),
									.instructions(instructions_dh),
									.waiting_on_writeback(waiting_on_writeback_dh),
									.enable_wait_for(enable_wait_for_hd),
									.set_wait_for(set_wait_for_hd),
									.branch_control(branch_em),
									.jump_control(jump_ef)
									
								);
	
	
	///////////////////////////////////////////////////////////
	///////////////////*FETCH STAGE*///////////////////////////
	///////////////////////////////////////////////////////////
	
	//The instruction address passback
	//Choosing the proper next address
	wire [31:0] branch_address_ef; //If branch, new address
	wire [31:0] jump_address_ef; //If branch, new address
	
	wire program_counter_source_mf; //If branch, change the source
	
	//Instructions
	wire [31:0] instructions_fd; //The fetched MIPS instructions from the instruction memory to the decoder

	//Program counter
	wire [31:0] pc_plus_four_fd; //The incremented program counter
	
	FetchStageWithRegisters f (	.clk(clk), .reset(reset), .pause(pause),
								.inst_i_valid(inst_i_valid), .inst_i(inst_i),
								.branch_address(branch_address_ef), .jump_address(jump_address_ef), .program_counter_source(program_counter_source_mf), .jump(jump_ef),
								.inst_o_valid(inst_o_valid), .inst_o_addr(inst_o_addr),
								.pc_plus_four(pc_plus_four_fd), .instruction(instructions_fd),
								.bubble(bubble_hd),
								.inst_delay_exception(inst_delay_exception)
								
								);
																	
	///////////////////////////////////////////////////////////
	//////////////////////*DECODE STAGE*///////////////////////
	///////////////////////////////////////////////////////////
	
	//The passback from the data memory stage
	wire [4:0] register_write_address_md;
	wire [31:0] register_write_data_wd;
	
	//The only control line to come into the decoder passed back from the memory stage.  This determines whether the register should write.
	wire register_write_md;

	//Pass through
	wire [31:0] pc_plus_four_de;
	
	//The control lines.  Coming out of the control stage, these will get passed forward over and over	
	wire register_destination_de;
	wire ALU_source_de;
	wire mem_to_register_de;
	wire register_write_de;
	wire memory_read_de;
	wire memory_write_de;
	wire branch_de;
	wire jump_de;
	wire [31:0] jump_address_de;
	wire [1:0] ALU_op_de;
		
	//The registers out
	wire [31:0] read_value_0_de;
	wire [31:0] read_value_1_de;
	
	//Sign extend
	wire [31:0] sign_extended_de;
	
	//Pass through instructions
	wire [4:0] instruction_20_16_de;
	wire [4:0] instruction_15_11_de;
	
	//Route instruction upwards to Hazard Detection Unit
	assign instructions_dh = instructions_fd;
	
	//Wire for holding debug value for control unit
	wire [9:0] bunch_debug;
							
	DecodeStageWithRegisters d ( .clk(clk),.reset(reset),.pause(pause),
					
					.instructions(instructions_fd),
					
					//Hazard Control Lines
					.bubble(bubble_hd),
					.waiting_on_writeback(waiting_on_writeback_dh),
					.enable_wait_for(enable_wait_for_hd),
					.set_wait_for(set_wait_for_hd),

					.register_write_md(register_write_md),
					.register_write_address(register_write_address_md), .register_write_data(register_write_data_wd),
					.pc_plus_four_in(pc_plus_four_fd), .pc_plus_four(pc_plus_four_de),
					.register_destination(register_destination_de), .ALU_source(ALU_source_de),
					.mem_to_register(mem_to_register_de), .register_write(register_write_de), 
					.memory_read(memory_read_de),.memory_write(memory_write_de),.branch(branch_de),.jump(jump_de),.jump_address(jump_address_de),.ALU_op(ALU_op_de),
					.read_value_0(read_value_0_de),.read_value_1(read_value_1_de),
					.sign_extended(sign_extended_de),
					.instruction_20_16(instruction_20_16_de), .instruction_15_11(instruction_15_11_de),
					
					.bunch_debug(bunch_debug)
					
					);


/*					assign debug0 = data_i_valid;
					assign debug1 = data_i;
					assign debug2 = instructions_dh;
					assign debug3 = register_write_de;
*/

					
	///////////////////////////////////////////////////////////
	/////////////////////*EXECUTE STAGE*///////////////////////
	///////////////////////////////////////////////////////////
	
	wire [31:0] ALU_result_em; // Output of ALU calculation
	wire [31:0] data_memory_data_em; // Routing data to be stored in memory from register to data memory
	wire memory_read_em; // Enables memory to read
	wire memory_write_em; // Enables memory to write
	wire ALU_zero_em; // Control bit for branch commands from the ALU
	wire register_write_em; // Control bit for register to write
	wire mem_to_register_em; // Control bit for register to pull from data memory
	wire [4:0] register_write_address_em; // Address for the register to write to
					
	ExecuteStageWithRegisters e (.clk(clk), .reset(reset), .pause(pause),

					//data inputs
					.pc_plus_four(pc_plus_four_de), .read_value_0(read_value_0_de), .read_value_1(read_value_1_de),

					//instruction words
					.sign_extended(sign_extended_de), .instruction_20_16(instruction_20_16_de), .instruction_15_11(instruction_15_11_de),
					
					//execute stage controls
					.ALU_source(ALU_source_de), .ALU_op(ALU_op_de), .register_destination(register_destination_de),
					
					//pass-through inputs
					.mem_to_register_input(mem_to_register_de),
					.register_write_input(register_write_de),
					.memory_read_input(memory_read_de),
					.memory_write_input(memory_write_de),
					.branch_input(branch_de),
					.jump_input(jump_de),
					.jump_address_input(jump_address_de),
										
					//outputs
					.branch_address(branch_address_ef),
					.ALU_result(ALU_result_em),
					.ALU_zero(ALU_zero_em),
					.register_write_address(register_write_address_em),
					.data_memory_data(data_memory_data_em),
					
					//pass-through outputs
					.mem_to_register(mem_to_register_em),
					.register_write(register_write_em),
					.memory_read(memory_read_em),
					.memory_write(memory_write_em),
					.branch(branch_em),
					.jump(jump_ef),
					.jump_address(jump_address_ef)

					);
	
	
	///////////////////////////////////////////////////////////
	///////////////////*MEMORY STAGE*//////////////////////////
	///////////////////////////////////////////////////////////	
	
	wire [31:0] data_memory_value_mw; // Output of Data Memory
	wire [31:0] ALU_result_mw; // Output of ALU passed onto write back stage
	wire mem_to_register_mw; // Control bit for register to pull from data memory
	wire concurrent_data_read_write_error;
					
	MemoryStageWithRegisters m (.clk(clk), .reset(reset), .pause(pause),
					
					.data_i_valid(data_i_valid), .data_i(data_i),
					.data_o_valid(data_o_valid), .data_o_rw(data_o_rw),
					.data_o_addr(data_o_addr), .data_o_value(data_o_value),
					
					.ALU_result_input(ALU_result_em),
					.data_memory_data_input(data_memory_data_em),
					.memory_read_input(memory_read_em),
					.memory_write_input(memory_write_em),
					
					.data_memory_value(data_memory_value_mw),
					.ALU_result(ALU_result_mw),
					
					.branch_input(branch_em),
					.ALU_zero(ALU_zero_em),
					.program_counter_source(program_counter_source_mf),
					
					.register_write_input(register_write_em),
					.mem_to_register_input(mem_to_register_em),
					.register_write_address_input(register_write_address_em),
					.register_write(register_write_md),
					
					.mem_to_register(mem_to_register_mw),
					.register_write_address(register_write_address_md),
					
					.data_delay_exception(data_delay_exception),
					.concurrent_data_read_write_error(concurrent_data_read_write_error)
					);	
	
	
	///////////////////////////////////////////////////////////
	//////////////////*WRITE BACK STAGE*///////////////////////
	///////////////////////////////////////////////////////////
	
	WriteBackStage w (.mem_to_register(mem_to_register_mw), .ALU_result(ALU_result_mw), .data_memory_value(data_memory_value_mw), .register_write_data(register_write_data_wd));
	
	
endmodule
